﻿// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using Coverlet.Core;
using Coverlet.Core.CoverageSamples.Tests;
using Coverlet.Core.Tests;
using Coverlet.Tests.Utils;
using Xunit;

namespace Coverlet.CoreCoverage.Tests
{
  public partial class CoverageTests
  {
    [Fact]
    public void ExcludeFilteredNestedAutogeneratedTypes()
    {
      string path = Path.GetTempFileName();
      try
      {
        FunctionExecutor.Run(async (string[] pathSerialize) =>
        {
          CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<ExcludeFilterNestedAutogeneratedTypes>(instance =>
                  {
                    instance.Run();

                    PropertyInfo stateProp = null;
                    foreach (Type type in ((Type)instance.GetType()).Assembly.GetTypes())
                    {
                      if (typeof(Issue_689).FullName == type.FullName)
                      {
                        Assert.Equal(0, (stateProp = type.GetProperty("State")).GetValue(null));
                        break;
                      }
                    }

                    foreach (Type type in ((Type)instance.GetType()).Assembly.GetTypes())
                    {
                      if (typeof(EventSource_Issue_689).FullName == type.FullName)
                      {
                        type.GetMethod("RaiseEvent").Invoke(null, null);
                        break;
                      }
                    }

                    Assert.Equal(2, stateProp.GetValue(null));

                    return Task.CompletedTask;
                  },
                  includeFilter: moduleFileName => [$"[{Path.GetFileNameWithoutExtension(moduleFileName)}*]*ExcludeFilterNestedAutogeneratedTypes", $"[{Path.GetFileNameWithoutExtension(moduleFileName)}*]*Issue_689"],
                  excludeFilter: moduleFileName => [$"[{Path.GetFileNameWithoutExtension(moduleFileName)}*]*NestedToFilterOut", $"[{Path.GetFileNameWithoutExtension(moduleFileName)}*]*Uncoverlet"],
                  persistPrepareResultToFile: pathSerialize[0]);

          return 0;
        }, [path]);

        TestInstrumentationHelper.GetCoverageResult(path)
        .Document("Instrumentation.ExcludeFilter.cs")
        .AssertLinesCovered(BuildConfiguration.Debug, (12, 1), (13, 1), (14, 1))
        .AssertLinesCovered(BuildConfiguration.Debug, (27, 1), (28, 1), (29, 1), (30, 1), (31, 1))
        .AssertLinesCovered(BuildConfiguration.Debug, (39, 2), (40, 2), (41, 2), (43, 5))
        .AssertLinesCovered(BuildConfiguration.Debug, (50, 1), (51, 1), (52, 1))
        .AssertNonInstrumentedLines(BuildConfiguration.Debug, 17, 21)
        .AssertNonInstrumentedLines(BuildConfiguration.Debug, 33, 36);
      }
      finally
      {
        File.Delete(path);
      }
    }

    [Fact]
    public void ExcludeFilteredTypes()
    {
      string path = Path.GetTempFileName();
      try
      {
        FunctionExecutor.Run(async (string[] pathSerialize) =>
        {
          CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<ExcludeFilterOuterTypes>(instance =>
                  {
                    Assert.Equal(42, instance.Run());
                    return Task.CompletedTask;
                  },
                  excludeFilter: moduleFileName => [$"[{Path.GetFileNameWithoutExtension(moduleFileName)}*]*ExcludeFilterOuterTypes"],
                  persistPrepareResultToFile: pathSerialize[0]);

          return 0;
        }, [path]);

        TestInstrumentationHelper.GetCoverageResult(path)
        .Document("Instrumentation.ExcludeFilter.cs")
        .AssertNonInstrumentedLines(BuildConfiguration.Debug, 1, 62)
        .AssertLinesCovered(BuildConfiguration.Debug, (66, 1), (68, 1));
      }
      finally
      {
        File.Delete(path);
      }
    }

    [Fact]
    public void ExcludeFilteredNestedTypes()
    {
      string path = Path.GetTempFileName();
      try
      {
        FunctionExecutor.Run(async (string[] pathSerialize) =>
        {
          CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<ExcludeFilterClass1>(instance =>
                  {
                    Assert.Equal(42, instance.Run());
                    return Task.CompletedTask;
                  },
                  excludeFilter: moduleFileName => [$"[{Path.GetFileNameWithoutExtension(moduleFileName)}*]*ExcludeFilterClass2"],
                  persistPrepareResultToFile: pathSerialize[0]);

          return 0;
        }, [path]);

        TestInstrumentationHelper.GetCoverageResult(path)
        .Document("Instrumentation.ExcludeFilter.cs")
        .AssertLinesCovered(BuildConfiguration.Debug, (73, 1))
        .AssertNonInstrumentedLines(BuildConfiguration.Debug, 75, 93);
      }
      finally
      {
        File.Delete(path);
      }
    }
  }
}
